package com.zfl.interceptor;

import com.zfl.utils.JwtUtils;
import com.zfl.utils.UserContextHolder;
import com.zfl.vo.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;


import java.io.PrintWriter;

/**
 * 权限拦截器：验证登录态 + 权限校验
 */
@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {

    // 依赖注入
    private final JwtUtils jwtUtils;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;

    // Redis Key常量
    private static final String USER_ROLE_KEY_PREFIX = "user:role:"; // 用户角色Hash的Key前缀
    private static final String PERM_URL_BIT_KEY = "perm:url:bit";   // URL-权限位Hash的Key
    private static final String ROLE_PERM_BIT_KEY_PREFIX = "role:perm:bit:"; // 角色-权限总和的Key前缀

    // 构造函数注入（避免使用@Autowired，更符合Spring最佳实践）
    public AuthInterceptor(JwtUtils jwtUtils, RedisTemplate<String, Object> redisTemplate, ObjectMapper objectMapper) {
        this.jwtUtils = jwtUtils;
        this.redisTemplate = redisTemplate;
        this.objectMapper = objectMapper;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // -------------------------- 1. 提取并验证Token --------------------------
        String token = request.getHeader("Authorization");
        // 校验Token格式（必须是Bearer + 空格 + Token）
        if (token == null || !token.startsWith("Bearer ")) {
            renderError(response, Result.fail(401, "请先登录（Token格式错误）"));
            return false;
        }
        // 提取纯Token（去除"Bearer "前缀）
        token = token.substring(7).trim();

        // 解析Token中的userId
        Long userId = jwtUtils.getUserIdFromToken(token);
        if (userId == null) {
            renderError(response, Result.fail(401, "登录已过期，请重新登录（Token无效）"));
            return false;
        }


        // -------------------------- 2. 从Redis获取用户角色ID --------------------------
        String userRoleKey = USER_ROLE_KEY_PREFIX + userId;
        // 从Hash结构中获取roleId（注意：Redis存储的是Object，需强转）
        Object roleIdObj = redisTemplate.opsForHash().get(userRoleKey, "roleId");
        if (roleIdObj == null) {
            renderError(response, Result.fail(401, "登录已过期，请重新登录（角色信息不存在）"));
            return false;
        }
        Long roleId = Long.valueOf(roleIdObj.toString()); // 转换为Long类型


        // -------------------------- 3. 获取当前请求URI对应的权限位 --------------------------
        String requestUri = request.getRequestURI();
        // 从Hash结构中获取当前URI对应的bitPosition（权限值，如1、2、4、8...）
        Object bitPositionObj = redisTemplate.opsForHash().get(PERM_URL_BIT_KEY, requestUri);
        if (bitPositionObj == null) {
            renderError(response, Result.fail(403, "接口未配置权限（URI：" + requestUri + "）"));
            return false;
        }
        Integer bitPosition = Integer.valueOf(bitPositionObj.toString()); // 转换为Integer类型


        // -------------------------- 4. 获取角色的权限总和 --------------------------
        String rolePermKey = ROLE_PERM_BIT_KEY_PREFIX + roleId;
        // 从String结构中获取角色的权限总和permBitSum
        Object permBitSumObj = redisTemplate.opsForValue().get(rolePermKey);
        if (permBitSumObj == null) {
            renderError(response, Result.fail(403, "角色未配置权限（角色ID：" + roleId + "）"));
            return false;
        }
        Integer permBitSum = Integer.valueOf(permBitSumObj.toString()); // 转换为Integer类型


        // -------------------------- 5. 位运算判断权限 --------------------------
        boolean hasPermission = (permBitSum & bitPosition) > 0;
        if (!hasPermission) {
            renderError(response, Result.fail(403, "无权限访问该接口（URI：" + requestUri + "）"));
            return false;
        }


        // -------------------------- 6. 存储用户信息到ThreadLocal --------------------------
        UserContextHolder.UserContext userContext = new UserContextHolder.UserContext();
        userContext.setUserId(userId);
        userContext.setRoleId(roleId);
        UserContextHolder.setUserContext(userContext);
        log.info("用户ID={} 权限校验通过，URI：{}", userId, requestUri);


        // 全部校验通过，放行
        return true;
    }

    /**
     * 请求结束后清理ThreadLocal，避免线程池复用导致数据残留
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        UserContextHolder.clear();
        log.debug("请求结束，清理ThreadLocal用户信息，URI：{}", request.getRequestURI());
    }

    /**
     * 向前端响应统一格式的错误信息
     */
    private void renderError(HttpServletResponse response, Result<?> result) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(200); // 业务状态由Result中的code决定
        PrintWriter writer = response.getWriter();
        writer.write(objectMapper.writeValueAsString(result)); // 转换为JSON
        writer.flush();
        writer.close();
    }
}